var wolframAlphaGoogle = {
  leaveAdsOnLoad: true,
	wolframGoogle_prefRoot: "",
	extensions_prefRoot: "",
	insertAfter: com.sidthemonkey.Utils.insertAfter,
	insertBefore: com.sidthemonkey.Utils.insertBefore,

	init: function (){
		this.wolframGoogle_prefRoot = new SidTheMonkey_PrefManager("extensions.wolframgoogle.");
		this.extensions_prefRoot = new SidTheMonkey_PrefManager("extensions.");
		this.setEnabled(this.getEnabled());
	},
	
	findLocationToInsertIframe: function (doc) {
		var location;
		location = doc.getElementById("center_col");
		if (!location) location = doc.getElementById("res");
		if (!location && console) console.log("Could not find location to insert iframe.")
		return location;
	},
	
	findLocationToInsertNav: function (doc) {
		var location;
		location = doc.getElementById("resultStats");//sff subform_ctrl
		if (!location) location = doc.getElementsByClassName("lsd")[0];
		if (!location && console) console.log("Could not find location to insert navbar")
		return location;
	},
	
	loadWolfGoogTopUi: function (doc, searchQuery, targetUrl) {
		//Check for ltr or rtl
		var textDirection = doc.body.getAttribute("dir");
		var isRtl = textDirection == "rtl" ? true : false;
		var floatSide = isRtl ? "left" : "right";
		this.addAllGlobalStyles(doc);
		var locationToInsertIframe = this.findLocationToInsertIframe (doc);
		var locationToInsertNav = this.findLocationToInsertNav(doc);
		if (!locationToInsertIframe||!locationToInsertNav){
			return;
		}
		var adsDiv = doc.getElementById("mbEnd");
    if (!this.leaveAdsOnLoad){
			if (adsDiv) adsDiv.style.display = "none";
		}
		//Create the navigation UI at the top of the page
		var wolframDivTopTable = this.createElement("td", 
				{"style": "vertical-align:bottom; padding-bottom: 4px;"},
				{}, doc);
    this.insertAfter(wolframDivTopTable,locationToInsertNav);
		var navBarLeftOffset = 300;
		var wolframDivTop = this.createElement("div", 
				{"id":"wolfram-div-top", "style":"overflow-y: hidden; overflow-x: hidden; float:" + floatSide + "; width:" + navBarLeftOffset + "px; display: compact; text-align:left;"}, // + floatSide + ";"},
				{}, doc);
    wolframDivTopTable.appendChild(wolframDivTop);
		//var selectedTab = this.wolframGoogle_prefRoot.getValue("selectedTab", "Wolfram");
		//Always show the Original tab first
		var selectedTab = "Original";
		//Check if Googlepedia is installed
		var enabledExtensions = this.extensions_prefRoot.getValue("enabledItems", null);
		var googlepediaInstalled = enabledExtensions.indexOf("{1ABADB6E-DC4B-11DA-9F70-791A9CD9513E}");
		if (googlepediaInstalled >= 0) googlepediaInstalled = true;
		else googlepediaInstalled = false;
		//Create the top buttons
		var originalButton = this.createElement("button", 
				{"id":"original-button", "type":"button", "title":"Show the original Google content (normally text ads).", "style":"display: inline; font: bold 84% 'trebuchet ms',helvetica,sans-serif; background-color:#fed; border:1px solid; border-color: #696 #363 #363 #696; margin-left: 2px; margin-right: 2px;"},
				{"textContent":"Original"}, doc);
		if (selectedTab == "Original")originalButton.setAttribute("class", "selectedButton");
		else {originalButton.setAttribute("class", "notSelectedButton");}
    wolframDivTop.appendChild(originalButton);
		originalButton.addEventListener("click", function(event){wolframAlphaGoogle.showAdsEvent(event);}, false);
		if (googlepediaInstalled){
			var googlepediaButton = this.createElement("button", 
					{"id":"googlepedia-button", "type":"button", "title":"Show the Googlepedia results.", "style":"display: inline; font: bold 84% 'trebuchet ms',helvetica,sans-serif; background-color:#fed; border:1px solid; border-color: #696 #363 #363 #696; margin-left: 2px; margin-right: 2px;"},
					{"textContent":"Googlepedia"}, doc);
			if (selectedTab == "Googlepedia")googlepediaButton.setAttribute("class", "selectedButton");
			else {googlepediaButton.setAttribute("class", "notSelectedButton");}
      wolframDivTop.appendChild(googlepediaButton);
			googlepediaButton.addEventListener("click", function(event){wolframAlphaGoogle.showGooglepediaEvent(event);}, false);
		}
		var wolframButton = this.createElement("button", 
				{"id":"wolfram-button", "type":"button", "title":"Loading Wolfram Alpha results.", "style":"display: inline; font: bold 84% 'trebuchet ms',helvetica,sans-serif; background-color:#fed; border:1px solid; border-color: #696 #363 #363 #696; background-image: url(chrome://global/skin/icons/loading_16.png); background-position: 1% 40%; background-repeat: no-repeat; margin-left: 2px; margin-right: 2px; padding-left:17px;"},
				{"textContent":"Wolfram|Alpha"}, doc);
		if (selectedTab == "Wolfram")wolframButton.setAttribute("class", "selectedButton");
		else {wolframButton.setAttribute("class", "notSelectedButton");}
    wolframDivTop.appendChild(wolframButton);
		wolframButton.addEventListener("click", function(event){wolframAlphaGoogle.showWolframEvent(event);}, false);
		var openInNewTab = this.createElement("a", 
				{"id":"wolfram-openInNewTab", "href":targetUrl, "target":"_blank", "title":"Open Wolfram Alpha in a new tab.", "style": "text-decoration: none;"},
				{"textContent":""}, doc);
    wolframDivTop.appendChild(openInNewTab);
		var loadingImage = this.createElement("img", 
				{"id":"open-wolfram-image", "src":"chrome://wolframgoogle/content/resources/link_external.png", "style":"display: inline; border: none;"},
				{}, doc);
    openInNewTab.appendChild(loadingImage);
		//Create the div for the iframe
		var wolframDiv = this.createElement("div",
				{"id":"wolfram-div", "style":"overflow-y: hidden; overflow-x: hidden; display: none; position:relative; left:100px z-index:99;"},//width:665px;float:" + "left" + ";
				{}, doc);
    this.insertBefore(wolframDiv,locationToInsertIframe);//locationToInsertIframe
    var googlePageHeight = doc.defaultView.getComputedStyle(doc.getElementById("res"),null).getPropertyValue("height");
		var googlePageHeightNum = parseFloat(googlePageHeight.replace("px", ""));
		var wolframIframe = this.createElement("iframe", 
				{"id":"wolfram-iframe", "src": "", "style":"overflow-y: hidden; overflow-x: hidden; border: none;", "width":660, "float":"left", "height":googlePageHeightNum * 3},
				{}, doc);
		wolframDiv.appendChild(wolframIframe);
		var showScrollbarLink = this.createElement("a", 
				{"id":"wolfram-showFrames", "toggleStatus":"show", "style": "text-align: " + floatSide + "; margin-top: 5px; margin-right: 5px; float: " + floatSide + "; color: blue;"},
				{"textContent":"Show scrollbar"}, doc);
    wolframDiv.appendChild(showScrollbarLink);
		showScrollbarLink.addEventListener("click",function (event){wolframAlphaGoogle.toggleScrollbar(event);},false);
	},

  loadWolframGoogle: function (doc) {
		if (!this.getEnabled())return;
		var domainMatch = this.checkDomain(doc.location.href, "google");
		if (domainMatch){
			var wolframIframe = doc.getElementById("wolfram-iframe");
      if (wolframIframe) return;
      var searchQuery = this.getQueryVariable("q", doc);
			if (!searchQuery) searchQuery = this.getValueOfParameterInUrl("q", doc.location.href);
      var targetUrl = this.buildWolframUrl(searchQuery);
			//Check for Google advanced searches and do nothing if found.
			//Only works when people use the URLs directly. Not if they select it from the Advanced search page.
			if (searchQuery.match(/^inurl|^related|^link|^allinurl|^allinanchor|^allintext|^allintitle/)){
				return;
			}
			this.loadWolfGoogTopUi(doc, searchQuery, targetUrl);
			var wolframIframe = doc.getElementById("wolfram-iframe");
			if (!wolframIframe) return;
			var loadUrlSafely = this.wolframGoogle_prefRoot.getValue("checkForFrameBuster", false);
			if (loadUrlSafely){
				wolframAlphaGoogle_iframeBuster.checkIfUrlHasFrameBuster(targetUrl, doc.location.href);
			}
			else {
			wolframIframe.src = targetUrl;
			wolframIframe.addEventListener ("load", function(event){wolframAlphaGoogle.checkWolframLoaded(event);}, false);
			}
    }
  },
	
	buildWolframUrl: function (query){
		var url = "http://www.wolframalpha.com/input/?i=" + query;
		var appendParameter = false;//Haven't got a reply from the Wolfram team so leaving this disabled.
		if (appendParameter){
			url += "&source=WAGFFAddon"
		}
		return url;
	},
	
	loadWolframInIframe: function (doc, targetUrl, loadedIframe){
		var wolframIframe = doc.getElementById("wolfram-iframe");
		wolframIframe.src = targetUrl;
		wolframIframe.addEventListener ("load", function(event){wolframAlphaGoogle.checkWolframLoaded(event);}, false);
	},
	
	adjustXmarksForSmallScreens: function (position,doc){
		if(!this.wolframGoogle_prefRoot.getValue("adjustXmarks", false)) return;
		for (var i=0; i<3; i++){
			var foxmarkIconObject = {};
			var foxmarkWhatsthisObject = {};
			foxmarkIconObject.relative = {"position":"relative","margin-left":"0px"};
			foxmarkWhatsthisObject.relative = {"margin-left":"40px","margin-top":"-17px"};
			foxmarkIconObject.absolute = {"position":"absolute","margin-left":"554px"};
			foxmarkWhatsthisObject.absolute = {"margin-left":"594px","margin-top":"12px"};
			var foxmarkIcon = doc.getElementById("foxmarks." + i);
			if (foxmarkIcon){
				foxmarkIcon.style.setProperty("position",foxmarkIconObject[position]["position"],null);
				foxmarkIcon.style.setProperty("margin-left",foxmarkIconObject[position]["margin-left"],null);
			}
			var foxmarkWhatsthis = doc.getElementById("foxmarks.whatsthis." + i);
			if (foxmarkWhatsthis){
				foxmarkWhatsthis.style.setProperty("margin-left",foxmarkWhatsthisObject[position]["margin-left"],null);
				foxmarkWhatsthis.style.setProperty("margin-top",foxmarkWhatsthisObject[position]["margin-top"],null);
			}
		}
	},
	
	addAllGlobalStyles: function (doc) {
		doc.body.style.setProperty("margin-right","0px",null);
		this.addGlobalStyle('.selectedButton { color:#FF826f;	} .notSelectedButton { color:#050 } #cnt { max-width:none }',doc);
	},
	
	toggleScrollbar: function (event) {
		var toggleStatus = event.target.getAttribute("toggleStatus");
		this[toggleStatus + "Scrollbar"](event);
	},

	showScrollbar: function (event) {
		var target = event ? event.target : content.document.getElementById("wolfram-iframe");
		var mainDoc = target.ownerDocument;
    var wolframIframe = mainDoc.getElementById("wolfram-iframe");
    if (!wolframIframe) return;
		wolframIframe.style.setProperty("overflow-y","scroll",null);
		var showToolbarButton = content.document.getElementById("wolfram-showFrames");
		showToolbarButton.textContent = "Hide Scrollbar";
		showToolbarButton.setAttribute("toggleStatus","hide");
	},
	
	hideScrollbar: function (event) {
		var mainDoc = event.target.ownerDocument;
    var wolframIframe = mainDoc.getElementById("wolfram-iframe");
    if (!wolframIframe) return;
		wolframIframe.style.setProperty("overflow-y","hidden",null);
		event.target.textContent = "Show Scrollbar";
		event.target.setAttribute("toggleStatus","show");
	},
	
	getValueOfParameterInUrl: function (parameterNameArray, url){
		var parameterValue = "";
		var hrefParameters = [];
		hrefParameters = url.split(/[\&\?\#]/);
		for (var i=0; i<parameterNameArray.length; i++) {
			var parameterName = parameterNameArray[i].toLowerCase();
			var currentQueryParaRegexString = "^" + parameterName + "$";
			var currentQueryParaRegex = new RegExp(currentQueryParaRegexString,"g");
			for (var j = 0; j < hrefParameters.length; j++)
			{
				var currentParaString = hrefParameters[j];
				var currentParaStringArray = [];
				var currentParaStringArray = currentParaString.split(/\=/);
				currentParaStringArray[0] = currentParaStringArray[0].toLowerCase();
				if (currentParaStringArray[0].match(currentQueryParaRegex))
				{
					parameterValue = currentParaStringArray[1];
					return parameterValue;
				}
			};
		};
		return parameterValue;
	},

	createElement: function (elementType, attributeObject, propertyObject, doc) {
		if (!doc) doc = document;
		var newElement = doc.createElement(elementType);
		for (var attr in attributeObject){
			newElement.setAttribute(attr, attributeObject[attr]);
		}
		for (var prop in propertyObject){
			newElement[prop] = propertyObject[prop];
		}
		return newElement;
	},
  
  checkWolframLoaded: function (event, doc, wolframIframe){
		if(event) {
			var mainDoc = event.target.ownerDocument;
			var wolframDoc = event.target.contentWindow.document;
			var wolframIframe = event.target;
		}
		else {
			var mainDoc = doc;
			var wolframDoc = wolframIframe.contentDocument;
		}
		if (!this.getEnabled())return;
    if (wolframDoc){
      var header = wolframDoc.getElementById("header");
    }
    if (header){
			var wolframResult = this.checkWolframResult (wolframDoc);
      this.hideElement("header", wolframDoc);
      this.hideElement("calculate", wolframDoc);
      this.hideElement("sidebar", wolframDoc);
      this.hideElement("footer", wolframDoc);
			this.hideElement("timeout", wolframDoc);
			//wolframDoc.getElementById("content").offsetLeft=0;
			mainDoc.getElementById("wolfram-button").style.setProperty('background-image','url(chrome://wolframgoogle/content/resources/' + wolframResult + '.png)',null);
			var resultsTooltips = {"kekkaAru": "Wolfram Alpha has a result for this search. Click here to show",
														 "wakaranai":"Wolfram Alpha has NO results for this search.",
														 "kaihatsu":"Wolfram Alpha has NO results for this search but functionality for this topic is under development."}
			mainDoc.getElementById("wolfram-button").title = resultsTooltips[wolframResult];
			//var selectedTab = this.wolframGoogle_prefRoot.getValue("selectedTab", "Wolfram");
      //Always show original tab
			var selectedTab = "Original";
			if (wolframResult == "kekkaAru"){
				this["show" + selectedTab](mainDoc);
			}
			else if (selectedTab == "Googlepedia"){
				this.showGooglepedia(mainDoc);
			}
			else {
				this.showOriginal(mainDoc);
			}
    }
  },

	showAdsEvent: function (event) {
		var mainDoc = event.target.ownerDocument;
		this.showOriginal(mainDoc, event.target);
		this.wolframGoogle_prefRoot.setValue("selectedTab", "Original");
	},

	showOriginal: function (mainDoc, button){
		if (button) {
			button.setAttribute("class", "selectedButton");
			mainDoc.getElementById("wolfram-button").setAttribute("class", "notSelectedButton");
			if (mainDoc.getElementById("googlepedia-button")) mainDoc.getElementById("googlepedia-button").setAttribute("class", "notSelectedButton");
		}
		mainDoc.getElementById("");
		var adjustXmarks = true;
		if (adjustXmarks){
			this.adjustXmarksForSmallScreens("absolute",mainDoc);
		}
		this.showElement("mbEnd",mainDoc);
		if (mainDoc.getElementById("center_col")) {
			mainDoc.getElementById("center_col").style.display="block";
		}
		else {
			mainDoc.getElementById("res").style.display="block";
		}
		if (mainDoc.getElementById("foot")) {
			mainDoc.getElementById("foot").style.display="block";
		}
		if (mainDoc.getElementById("leftnav")) {
			mainDoc.getElementById("leftnav").style.display="block";
		}
		this.hideElement("wolfram-div",mainDoc);
		this.hideElement("wikibox",mainDoc);
		this.hideElement("showGooglepediaBox",mainDoc);
	},

	showWolframEvent: function (event) {
		var mainDoc = event.target.ownerDocument;
		this.showWolfram(mainDoc, event.target);
		this.wolframGoogle_prefRoot.setValue("selectedTab", "Wolfram");
	},

	showWolfram: function (mainDoc, button){
		if (button) {
			button.setAttribute("class", "selectedButton");
			mainDoc.getElementById("original-button").setAttribute("class", "notSelectedButton");
			if (mainDoc.getElementById("googlepedia-button")) mainDoc.getElementById("googlepedia-button").setAttribute("class", "notSelectedButton");
		}
		var adjustXmarks = true;
		if (adjustXmarks){
			this.adjustXmarksForSmallScreens("relative",mainDoc);
		}
		this.showElement("wolfram-div",mainDoc);
		this.hideElement("mbEnd",mainDoc);
		this.hideElement("center_col",mainDoc);
		this.hideElement("foot",mainDoc);
		this.hideElement("leftnav",mainDoc);
		this.hideElement("wikibox",mainDoc);
		this.hideElement("showGooglepediaBox",mainDoc);
		var alwaysShowScrollbars = this.wolframGoogle_prefRoot.getValue("alwaysShowScrollbars", false);
		if (alwaysShowScrollbars){
			this.showScrollbar();
			this.hideElement("wolfram-showFrames",mainDoc);
		}
	},

	showGooglepediaEvent: function (event, button) {
		var mainDoc = event.target.ownerDocument;
		this.showGooglepedia(mainDoc, event.target);
		this.wolframGoogle_prefRoot.setValue("selectedTab", "Googlepedia");
	},

	showGooglepedia: function (mainDoc, button){
		if (button) {
			button.setAttribute("class", "selectedButton");
			mainDoc.getElementById("original-button").setAttribute("class", "notSelectedButton");
			mainDoc.getElementById("wolfram-button").setAttribute("class", "notSelectedButton");
		}
		this.showElement("wikibox",mainDoc);
		this.showElement("showGooglepediaBox",mainDoc);
		this.hideElement("wolfram-div",mainDoc);
		this.hideElement("mbEnd",mainDoc);
	},
	
	checkWolframResult: function (wolframDoc){
		var resultType = "";
		if (wolframDoc.getElementById("future-img"))resultType = "kaihatsu";
		else if (wolframDoc.getElementById("splat"))resultType = "wakaranai";
		else resultType = "kekkaAru";
		return resultType
	},

	setEnabled: function (status){
		this.wolframGoogle_prefRoot.setValue("enabled", status);
		if (status) {
			document.getElementById("status-bar-wolframgoogle").setAttribute("image", "chrome://wolframgoogle/content/resources/wolfram_favicon.png");
			document.getElementById("status-bar-wolframgoogle").setAttribute("tooltiptext", "Wolfram Alpha Google is enabled. Click here to disable.");			
		}
		else {
			document.getElementById("status-bar-wolframgoogle").setAttribute("image", "chrome://wolframgoogle/content/resources/wolfram_favicon_disabled.png");
			document.getElementById("status-bar-wolframgoogle").setAttribute("tooltiptext", "Wolfram Alpha Google is disabled. Click here to enable.");			
		}
	},
	
	getEnabled: function (){
		return this.wolframGoogle_prefRoot.getValue("enabled", true);
	},

	checkDomain: function (currentUrl, matchString){
		var domain = currentUrl;
		domain = domain.replace("http://", "");
		domain = domain.substr(0,domain.indexOf("/"));
		var matched = domain.match(matchString);
		var ignoredDomainsPref = this.wolframGoogle_prefRoot.getValue("ignoredDomains", false);
		var domainsToIgnore = ignoredDomainsPref ? ignoredDomainsPref.split(",") : ["images", "video", "maps", "news", "mail", "books", "translate"];
		for (var i=0; i<domainsToIgnore.length; i++){
			if (domain.match(domainsToIgnore[i])){
				return false;
			}
		}
		return matched;
	},

	hideStatusBarIcon: function (event) {
		var statusbarIcon = document.getElementById("status-bar-wolframgoogle");
		var hideStatusBarIcon = this.wolframGoogle_prefRoot.getValue("hideStatusBarIcon", false);
		if (hideStatusBarIcon){
			statusbarIcon.style.display = "none";
		}
	},

  // Thanks to Pete Freitag via Googlepedia for this very useful function
  getQueryVariable: function (variable, mainDoc) {
  	var query = mainDoc.location.search.substring(1);
		var vars = query.split("&");
  	for (var i=0;i<vars.length;i++) {
  		var pair = vars[i].split("=");
  		if (pair[0] == variable) {
  			return pair[1];
  		}
  	}
  	return ''; 
  },
	
	//This one also thanks to Googlepedia but modified
	addGlobalStyle: function (css, doc) {
		if (!doc) doc = document;
		var head, style;
		head = doc.getElementsByTagName('head')[0];
		if (!head) return;
		style = doc.createElement('style');
		style.type = 'text/css';
		style.innerHTML = css;
		head.appendChild(style);
	},

  removeElement: function (elementId, doc){
    var currentElement = doc.getElementById(elementId);
    if (currentElement) currentElement.parentNode.removeChild(currentElement); 
  },

  hideElement: function (elementId, doc){
    if (!doc) doc = document;
    var currentElement = doc.getElementById(elementId);
    if (currentElement) currentElement.style.display="none"
  },

  showElement: function (elementId, doc){
    if (!doc) doc = document;
    var currentElement = doc.getElementById(elementId);
    if (currentElement) currentElement.style.display="inline"
  },
}

function wolframAlphaGoogle_PageLoad(event)
{
  if (event.originalTarget instanceof HTMLDocument) {
    var doc = event.originalTarget;
    if (event.originalTarget.defaultView.frameElement) {
      // Frame within a tab was loaded. doc should be the root document of
      // the frameset. If you don't want do anything when frames/iframes
      // are loaded in this web page, uncomment the following line:
      // return;
      // Find the root document:
      //Iframes load here so check if its a wolfram frame and then return.
      if (doc.location.href.match("wolframalpha.com")){
      return;
			//wolframAlphaGoogle.checkWolframLoaded();
      }
      while (doc.defaultView.frameElement) {
        doc=doc.defaultView.frameElement.ownerDocument;
      }
    }
    wolframAlphaGoogle.loadWolframGoogle (doc);
  }
}

// do not try to add a callback until the browser window has
// been initialised. We add a callback to the tabbed browser
// when the browser's window gets loaded.
window.addEventListener(
  "load",
  function () {
    // Add a callback to be run every time a document loads.
    // note that this includes frames/iframes within the document
		wolframAlphaGoogle.init();
    gBrowser.addEventListener("load", wolframAlphaGoogle_PageLoad, true);
  },
  false
);

// When no longer needed
//gBrowser.removeEventListener("load", wolframAlphaGoogle_PageLoad, true);

//----------------------------------------------------------------



SidTheMonkey_PrefManager.MIN_INT_32 = -0x80000000;
SidTheMonkey_PrefManager.MAX_INT_32 = 0x7FFFFFFF;

/**
 * Simple API on top of preferences for greasemonkey.
 * Construct an instance by passing the startPoint of a preferences subtree.
 * "greasemonkey." prefix is assumed.
 */
function SidTheMonkey_PrefManager(startPoint) {
  if (!startPoint) {
    startPoint = "";
  }

  //startPoint = "greasemonkey." + startPoint;

  var pref = Components.classes["@mozilla.org/preferences-service;1"]
                       .getService(Components.interfaces.nsIPrefService)
                       .getBranch(startPoint);

  var observers = {};
  const nsISupportsString = Components.interfaces.nsISupportsString;

  /**
   * whether a preference exists
   */
  this.exists = function(prefName) {
    return pref.getPrefType(prefName) != 0;
  };

  /**
   * enumerate preferences
   */
  this.listValues = function() {
    return pref.getChildList("", {});
  }

  /**
   * returns the named preference, or defaultValue if it does not exist
   */
  this.getValue = function(prefName, defaultValue) {
    var prefType = pref.getPrefType(prefName);

    // underlying preferences object throws an exception if pref doesn't exist
    if (prefType == pref.PREF_INVALID) {
      return defaultValue;
    }

    try {
      switch (prefType) {
        case pref.PREF_STRING:
          return pref.getComplexValue(prefName, nsISupportsString).data;
        case pref.PREF_BOOL:
          return pref.getBoolPref(prefName);
        case pref.PREF_INT:
          return pref.getIntPref(prefName);
      }
    } catch(ex) {
      return defaultValue != undefined ? defaultValue : null;
    }
    return null;
  };

  /**
   * sets the named preference to the specified value. values must be strings,
   * booleans, or integers.
   */
  this.setValue = function(prefName, value) {
    var prefType = typeof(value);
    var goodType = false;

    switch (prefType) {
      case "string":
      case "boolean":
        goodType = true;
        break;
      case "number":
        if (value % 1 == 0 &&
            value >= GM_PrefManager.MIN_INT_32 &&
            value <= GM_PrefManager.MAX_INT_32) {
          goodType = true;
        }
        break;
    }

    if (!goodType) {
      throw new Error("Unsupported type for GM_setValue. Supported types " +
                      "are: string, bool, and 32 bit integers.");
    }

    // underlying preferences object throws an exception if new pref has a
    // different type than old one. i think we should not do this, so delete
    // old pref first if this is the case.
    if (this.exists(prefName) && prefType != typeof(this.getValue(prefName))) {
      this.remove(prefName);
    }

    // set new value using correct method
    switch (prefType) {
      case "string":
        var str = Components.classes["@mozilla.org/supports-string;1"]
                            .createInstance(nsISupportsString);
        str.data = value;
        pref.setComplexValue(prefName, nsISupportsString, str);
        break;
      case "boolean":
        pref.setBoolPref(prefName, value);
        break;
      case "number":
        pref.setIntPref(prefName, Math.floor(value));
        break;
    }
  };

  /**
   * deletes the named preference or subtree
   */
  this.remove = function(prefName) {
    pref.deleteBranch(prefName);
  };

  /**
   * call a function whenever the named preference subtree changes
   */
  this.watch = function(prefName, watcher) {
    // construct an observer
    var observer = {
      observe:function(subject, topic, prefName) {
        watcher(prefName);
      }
    };

    // store the observer in case we need to remove it later
    observers[watcher] = observer;

    pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal).
      addObserver(prefName, observer, false);
  };

  /**
   * stop watching
   */
  this.unwatch = function(prefName, watcher) {
    if (observers[watcher]) {
      pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal).
        removeObserver(prefName, observers[watcher]);
    }
  };
}

window.addEventListener("load", function(e) { wolframAlphaGoogle.hideStatusBarIcon(e); }, false);
